﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows.Forms;
using Compiler.LabLogic;

namespace Compiler.LabForms
{
    public partial class TestForm : Form
    {
        private const int MaxQuestions = 12;
        private List<TestQuestion> _questions;
        private TestQuestion _currentQuestion;
        private int _correctCount;

        public TestForm()
        {
            InitializeComponent();
        }

        private void TestForm_Load(object sender, EventArgs e)
        {
            _correctCount = 0;
            _questions = new List<TestQuestion>
            {
                new TestQuestion("Компилятор ...")
                    .AddAnswer(new TestAnswer("преобразует команды языка высокого уровня в машинный язык, также выполняет проверку программы на языке высокого уровня.", true))
                    .AddAnswer(new TestAnswer("преобразует команды языка высокого уровня в машинный язык.", false))
                    .AddAnswer(new TestAnswer("преобразует команды языка машинного уровня в двоичный вид, также выполняет проверку программы на языке машинного уровня.", false))
                    .AddAnswer(new TestAnswer("преобразует команды языка машинного уровня в двоичный вид.", false)),
                new TestQuestion("Целью компилятора является ...")
                    .AddAnswer(new TestAnswer("трансляция программы написанной на языке программирования высокого уровня в машинные коды некоторого компьютера.", true))
                    .AddAnswer(new TestAnswer("трансляция программы написанной на языке программирования высокого уровня в двоичные коды некоторого компьютера.", false))
                    .AddAnswer(new TestAnswer("трансляция программы написанной на языке программирования машинного уровня в двоичные коды некоторого компьютера.", false))
                    .AddAnswer(new TestAnswer("проверка программы на языке высокого уровня.", false)),
                new TestQuestion("Наиболее существенная часть любого процесса компиляции - это ...")
                    .AddAnswer(new TestAnswer("выделение в исходной программе элементарных составляющих таких как идентификаторы, ограничители, операторы числа.", true))
                    .AddAnswer(new TestAnswer("проверка текста программы.", false))
                    .AddAnswer(new TestAnswer("создание исполняемого файла.", false))
                    .AddAnswer(new TestAnswer("построение дерева разбора.", false)),
                new TestQuestion("Лексический анализатор - это ...")
                    .AddAnswer(new TestAnswer("сканер, последовательно считывающий строки исходной программы, разбивающий их на лексемы и создающий несколько таблиц, используемых на различных этапах.", true))
                    .AddAnswer(new TestAnswer("сканер, параллельно считывающий строки исходной программы, разбивающий их на лексемы и создающий несколько таблиц, используемых на различных этапах.", false))
                    .AddAnswer(new TestAnswer("сканер, последовательно считывающий строки исходной программы и проверяющий их на принадлежность языку программирования.", false))
                    .AddAnswer(new TestAnswer("сканер, параллельно считывающий строки исходной программы и проверяющий их на принадлежность языку программирования.", false)),
                new TestQuestion("Лексический анализатор заполняет таблицы ...")
                    .AddAnswer(new TestAnswer("лексем.", false))
                    .AddAnswer(new TestAnswer("лексем и констант.", false))
                    .AddAnswer(new TestAnswer("констант и переменных.", false))
                    .AddAnswer(new TestAnswer("лексем, констант и переменных.", true)),
                new TestQuestion("Для облегчения процесса компиляции, язык высокого уровня ...")
                    .AddAnswer(new TestAnswer("описывается в терминах некоторой грамматики.", true))
                    .AddAnswer(new TestAnswer("должен быть представлен в форме Бэкуса-Наура.", false))
                    .AddAnswer(new TestAnswer("описывается командами более низкого уровня.", false))
                    .AddAnswer(new TestAnswer("должен быть представлен в машинном коде.", false)),
                new TestQuestion("Алфавит - это ...")
                    .AddAnswer(new TestAnswer("конечное множество символов.", true))
                    .AddAnswer(new TestAnswer("конечное множество символов плюс все терминальные символы.", false))
                    .AddAnswer(new TestAnswer("конечное множество символов плюс все нетерминальные символы.", false))
                    .AddAnswer(new TestAnswer("множество символов плюс все терминальные и нетерминальные символы.", false)),
                new TestQuestion("Выберите несуществующий тип грамматики.")
                    .AddAnswer(new TestAnswer("Неограниченные. Все правила имеют вид: α->β.", false))
                    .AddAnswer(new TestAnswer("Контекстно-зависимые (неукорачивающие).", false))
                    .AddAnswer(new TestAnswer("Контекстно-свободные.", false))
                    .AddAnswer(new TestAnswer("Постоянные.", true)),
                new TestQuestion("Выберите утверждение, которое не является характеристикой нормальной формы Бэкуса-Наура.")
                    .AddAnswer(new TestAnswer("Используется для описания грамматики языка.", false))
                    .AddAnswer(new TestAnswer("Терминальные символы записывают как обычные символы.", false))
                    .AddAnswer(new TestAnswer("Нетерминальные символы записываются как имена в угловых скобках.", false))
                    .AddAnswer(new TestAnswer("Терминальные символы записываются как имена в угловых скобках.", true)),
                new TestQuestion("Выберите элемент, отсутствующий в распознавателе языка.")
                    .AddAnswer(new TestAnswer("Считывающее устройство.", false))
                    .AddAnswer(new TestAnswer("Записывающее устройство.", true))
                    .AddAnswer(new TestAnswer("Устройство управления.", false))
                    .AddAnswer(new TestAnswer("Внешняя память.", false)),
                new TestQuestion("Сентенциальной формой грамматики G ...")
                    .AddAnswer(new TestAnswer("называется цепочка, выводимая из начального нетерминала грамматики G.", true))
                    .AddAnswer(new TestAnswer("называется цепочка, выводимая из начального терминала грамматики G.", false))
                    .AddAnswer(new TestAnswer("называется множество всех цепочек, выводимых из начального нетерминала грамматики G.", false))
                    .AddAnswer(new TestAnswer("называется множество всех цепочек, выводимых из начального терминала грамматики G.", false)),
                new TestQuestion("Выберите неверное утверждение об эквивалентных грамматиках.")
                    .AddAnswer(new TestAnswer("Эквивалентные грамматики должны иметь хотя бы пересекающиеся множества терминальных символов.", true))
                    .AddAnswer(new TestAnswer("Множество нетерминальных символов, могут отличаться.", false))
                    .AddAnswer(new TestAnswer("Правила грамматики и целевой символ могут отличаться.", false))
                    .AddAnswer(new TestAnswer("Множество терминальных и нетерминальных символов, правила грамматики и целевой символ должны быть эквивалентны.", false)),
                new TestQuestion("Выберите верное утверждение.")
                    .AddAnswer(new TestAnswer("Вывод называется левосторонним, если в нем на каждом шаге вывода правила грамматики применяются всегда к крайнему левому нетерминальному символу в цепочке.", true))
                    .AddAnswer(new TestAnswer("Вывод называется левосторонним, если в нем на каждом шаге вывода правила грамматики применяются всегда к крайнему левому терминальному символу в цепочке.", false))
                    .AddAnswer(new TestAnswer("Вывод называется левосторонним, если в нем на каждом шаге вывода правила грамматики применяются всегда к крайнему левому нетерминальному символу в языке.", false))
                    .AddAnswer(new TestAnswer("Вывод называется левосторонним, если в нем на каждом шаге вывода правила грамматики применяются всегда к крайнему левому терминальному символу в языке.", false)),
                new TestQuestion("Выберите верное утверждение.")
                    .AddAnswer(new TestAnswer("Вывод называется правосторонним, если в нем на каждом шаге вывода правила грамматики применяются всегда к крайнему правому нетерминальному символу в цепочке.", true))
                    .AddAnswer(new TestAnswer("Вывод называется правосторонним, если в нем на каждом шаге вывода правила грамматики применяются всегда к крайнему правому терминальному символу в цепочке.", false))
                    .AddAnswer(new TestAnswer("Вывод называется правосторонним, если в нем на каждом шаге вывода правила грамматики применяются всегда к крайнему правому нетерминальному символу в языке.", false))
                    .AddAnswer(new TestAnswer("Вывод называется правосторонним, если в нем на каждом шаге вывода правила грамматики применяются всегда к крайнему правому терминальному символу в языке.", false)),
                new TestQuestion("Лексический анализатор используется для ...")
                    .AddAnswer(new TestAnswer("распознавания элементарных конструкций, синтаксическое описание которых можно осуществить с применением праволинейных грамматик.", true))
                    .AddAnswer(new TestAnswer("распознавания элементарных конструкций, синтаксическое описание которых можно осуществить с применением леволинейных грамматик.", false))
                    .AddAnswer(new TestAnswer("распознавания неэлементарных конструкций, синтаксическое описание которых можно осуществить с применением праволинейных грамматик.", false))
                    .AddAnswer(new TestAnswer("распознавания неэлементарных конструкций, синтаксическое описание которых можно осуществить с применением леволинейных грамматик.", false)),
                new TestQuestion("На этапе лексического анализа символы, составляющие исходную программу, ...")
                    .AddAnswer(new TestAnswer("группируются в отдельные элементы, называемые лексемами.", true))
                    .AddAnswer(new TestAnswer("группируются в отдельные элементы, называемые терминальными символами.", false))
                    .AddAnswer(new TestAnswer("группируются в отдельные элементы, называемые нетерминальными символами.", false))
                    .AddAnswer(new TestAnswer("группируются в отдельные элементы, называемые целевыми символами.", false)),
                new TestQuestion("Выберите неверное высказывание о лексическом анализе.")
                    .AddAnswer(new TestAnswer("Лексический анализатор прост в организации.", true))
                    .AddAnswer(new TestAnswer("В исходной программе замена идентификаторов констант, ограничителей и служебных слов лексемами делает представление программы более удобным для дальнейшей обработки.", false))
                    .AddAnswer(new TestAnswer("Лексический анализ уменьшает длину программы, устраняя из её исходного представления несущественные пробелы и комментарии.", false))
                    .AddAnswer(new TestAnswer("Если будет изменена кодировка в исходном представлении программы, то это отразится только на лексическом анализаторе.", false)),
                new TestQuestion("Выберите тип лексем который не принято выделять на стадии лексического анализа.")
                    .AddAnswer(new TestAnswer("Разделители.", true))
                    .AddAnswer(new TestAnswer("Ограничители.", false))
                    .AddAnswer(new TestAnswer("Служебные слова.", false))
                    .AddAnswer(new TestAnswer("Идентификаторы.", false)),
                new TestQuestion("Получение кодов идентификаторов производится ...")
                    .AddAnswer(new TestAnswer("последовательно по тексту программы, начиная с начала.", true))
                    .AddAnswer(new TestAnswer("параллельно по строчкам программы, начиная с начала.", false))
                    .AddAnswer(new TestAnswer("последовательно по тексту программы, начиная с конца.", false))
                    .AddAnswer(new TestAnswer("параллельно по строчкам программы, начиная с конца.", false))
            };
            
            foreach (var testQuestion in _questions)
            {
                Utils.MixList(testQuestion.Answers);
            }

            Utils.MixList(_questions);

            var number = 1;
            foreach (var question in _questions)
            {
                question.Number = number;
                number++;
            }

            _currentQuestion = _questions[0];
            questionText.Text = _currentQuestion.Text;
            label1.Text = _currentQuestion.Answers[0].Text;
            label2.Text = _currentQuestion.Answers[1].Text;
            label3.Text = _currentQuestion.Answers[2].Text;
            label4.Text = _currentQuestion.Answers[3].Text;
            numberLabel.Text = @"Вопрос №" + _currentQuestion.Number;
        }

        private void nextButton_Click(object sender, EventArgs e)
        {
            if (!answer1.Checked && !answer2.Checked && !answer3.Checked && !answer4.Checked)
            {
                MessageBox.Show(@"Необходимо выбрать один из вариантов ответа", @"Внимание");
            }
            else
            {
                if (answer1.Checked)
                {
                    if (_currentQuestion.Answers[0].Right)
                    {
                        _correctCount++;    
                    }
                }
                if (answer2.Checked)
                {
                    if (_currentQuestion.Answers[1].Right)
                    {
                        _correctCount++;
                    }
                }
                if (answer3.Checked)
                {
                    if (_currentQuestion.Answers[2].Right)
                    {
                        _correctCount++;
                    }
                }
                if (answer4.Checked)
                {
                    if (_currentQuestion.Answers[3].Right)
                    {
                        _correctCount++;
                    }
                }
                if (_currentQuestion.Number < MaxQuestions)
                {
                    _currentQuestion = _questions[_currentQuestion.Number];
                    questionText.Text = _currentQuestion.Text;
                    label1.Text = _currentQuestion.Answers[0].Text;
                    label2.Text = _currentQuestion.Answers[1].Text;
                    label3.Text = _currentQuestion.Answers[2].Text;
                    label4.Text = _currentQuestion.Answers[3].Text;
                    answer1.Checked = false;
                    answer2.Checked = false;
                    answer3.Checked = false;
                    answer4.Checked = false;
                    numberLabel.Text = @"Вопрос №" + _currentQuestion.Number;
                }
                else
                {
                    Close();
                    Lab.GetLab().TestCorrectAnswers = _correctCount;
                    Lab.GetLab().TestCorrectPercentage = Math.Round(Convert.ToDouble(_correctCount)/12.0*100.0, 1);
                    Lab.GetLab().TestComplete = true;
                    MessageBox.Show(@"Тестирование завершено. Правильных ответов: " + _correctCount.ToString(CultureInfo.InvariantCulture), @"Сообщение");    
                }
            }
        }

        private void label1_Click(object sender, EventArgs e)
        {
            answer1.Checked = true;
        }

        private void label2_Click(object sender, EventArgs e)
        {
            answer2.Checked = true;
        }

        private void label3_Click(object sender, EventArgs e)
        {
            answer3.Checked = true;
        }

        private void label4_Click(object sender, EventArgs e)
        {
            answer4.Checked = true;
        }
    }
}
